package stringutil

import (
	"fmt"
	"strconv"
)

func toInt(str string, bitSize int, defaultValue int64) (int64, error) {
	res, err := strconv.ParseInt(str, 10, bitSize)
	if err != nil {
		res = defaultValue
	}
	return res, err
}

func ToInt8(str string, defaultValue int64) (int8, error) {
	res, err := toInt(str, 8, defaultValue)
	return int8(res), err
}

func ToInt16(str string, defaultValue int64) (int16, error) {
	res, err := toInt(str, 16, defaultValue)
	return int16(res), err
}

func ToInt32(str string, defaultValue int64) (int32, error) {
	res, err := toInt(str, 32, defaultValue)
	return int32(res), err
}

func ToInt64(str string, defaultValue int64) (int64, error) {
	return toInt(str, 64, defaultValue)
}

func toUint(str string, bitSize int, defaultValue uint64) (uint64, error) {
	res, err := strconv.ParseUint(str, 10, bitSize)
	if err != nil {
		res = defaultValue
	}
	return res, err
}

func ToUint8(str string, defaultValue uint64) (uint8, error) {
	res, err := toUint(str, 8, defaultValue)
	return uint8(res), err
}

func ToUint16(str string, defaultValue uint64) (uint16, error) {
	res, err := toUint(str, 16, defaultValue)
	return uint16(res), err
}

func ToUint32(str string, defaultValue uint64) (uint32, error) {
	res, err := toUint(str, 32, defaultValue)
	return uint32(res), err
}

func ToUint64(str string, defaultValue uint64) (uint64, error) {
	return toUint(str, 64, defaultValue)
}

func ToFloat32(str string, defaultValue float64) (float32, error) {
	res, err := strconv.ParseFloat(str, 32)
	if err != nil {
		res = defaultValue
	}
	return float32(res), err
}

func ToFloat64(str string, defaultValue float64) (float64, error) {
	res, err := strconv.ParseFloat(str, 64)
	if err != nil {
		res = defaultValue
	}
	return res, err
}

func ToBoolean(v interface{}) (val bool, err error) {
	if v != nil {
		switch vt := v.(type) {
		case bool:
			return vt, nil
		case string:
			switch vt {
			case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On":
				return true, nil
			case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off":
				return false, nil
			}
		case int8, int32, int64:
			strV := fmt.Sprintf("%d", vt)
			if strV == "1" {
				return true, nil
			} else if strV == "0" {
				return false, nil
			}
		case float64:
			if vt == 1.0 {
				return true, nil
			} else if vt == 0.0 {
				return false, nil
			}
		}
		return false, fmt.Errorf("parsing %q: invalid syntax", v)
	}
	return false, fmt.Errorf("parsing <nil>: invalid syntax")
}

func ToString(obj interface{}) string {
	res := fmt.Sprintf("%v", obj)
	return res
}
